package com.ikas.ai.server.module.cockpit.service;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.github.pagehelper.PageInfo;
import com.google.common.collect.Lists;
import com.ikas.ai.consts.MachineAndWorkConditionConst;
import com.ikas.ai.consts.TableDictConsts;
import com.ikas.ai.enums.MeteTypeEnum;
import com.ikas.ai.enums.redis.RedisKeyEnum;
import com.ikas.ai.model.PageQuery;
import com.ikas.ai.server.error.BusinessException;
import com.ikas.ai.server.module.alarm.dao.UnitDeteriorationAlarmDAO;
import com.ikas.ai.server.module.alarm.enums.SolvedEnum;
import com.ikas.ai.server.module.alarm.model.UnitDeteriorationAlarm;
import com.ikas.ai.server.module.assessment.model.vo.AwfResultDetailCalVo;
import com.ikas.ai.server.module.assessment.service.AssessModelService;
import com.ikas.ai.server.module.assessment.service.AssessWfResultService;
import com.ikas.ai.server.module.cockpit.model.dto.*;
import com.ikas.ai.server.module.cockpit.model.vo.UpAndDownWaterLevelVo;
import com.ikas.ai.server.module.condition.model.WorkConditionFlow;
import com.ikas.ai.server.module.condition.model.WorkConditionStep;
import com.ikas.ai.server.module.condition.model.WorkConditionStepDetail;
import com.ikas.ai.server.module.condition.service.WorkConditionFlowService;
import com.ikas.ai.server.module.condition.service.WorkConditionStepDetailService;
import com.ikas.ai.server.module.condition.service.WorkConditionStepService;
import com.ikas.ai.server.module.data.dorisDao.DorisYcDataDao;
import com.ikas.ai.server.module.data.dorisDao.DorisYxDataDao;
import com.ikas.ai.server.module.data.enums.MeteModelUse;
import com.ikas.ai.server.module.data.model.BaseMete;
import com.ikas.ai.server.module.data.model.doris.DorisYcData;
import com.ikas.ai.server.module.data.model.doris.DorisYxData;
import com.ikas.ai.server.module.data.model.tdengine.RealDataHis;
import com.ikas.ai.server.module.data.service.DorisYcDataService;
import com.ikas.ai.server.module.data.tdDao.DataHisTdMapper;
import com.ikas.ai.server.module.morningpaper.dao.RuntimeDataStatisticsDao;
import com.ikas.ai.server.module.morningpaper.model.po.RuntimeDataStatistics;
import com.ikas.ai.server.module.morningpaper.service.MorningPaperVariablesService;
import com.ikas.ai.server.module.morningpaper.service.RuntimeDataStatisticsService;
import com.ikas.ai.server.module.steady.dao.SteadyAlarmDataMapper;
import com.ikas.ai.utils.ObjectUtil;
import com.ikas.ai.utils.PageExUtil;
import com.ikas.ai.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 驾驶舱
 *
 * @author tang.xuandong
 * @version 1.0.0
 * @date 2023/5/12 9:52
 */
@Service
@Slf4j
public class CockpitService {


    @Value("${cockpit.mete-his.time-limit.year:0}")
    Integer yearLimit;
    @Value("${cockpit.mete-his.time-limit.month:1}")
    Integer monthLimit;
    @Value("${cockpit.mete-his.time-limit.day:0}")
    Integer dayLimit;
    @Value("${cockpit.assess.sleep.seconds:3}")
    Integer sleepSeconds;
    private static final BigDecimal NUM_ONE = BigDecimal.valueOf(1.00);
    private static final BigDecimal NUM_ZERO = BigDecimal.valueOf(0.00);
    private static final BigDecimal NUM_HUNDRED = BigDecimal.valueOf(100.00);

    @Autowired
    WorkConditionFlowService workConditionFlowService;
    @Autowired
    WorkConditionStepService workConditionStepService;
    @Autowired
    WorkConditionStepDetailService workConditionStepDetailService;
    @Autowired
    DataHisTdMapper dataHisTdMapper;
    @Autowired
    AssessModelService assessModelService;
    @Autowired
    AssessWfResultService assessWfResultService;
    @Autowired
    private DorisYxDataDao dorisYxDataDao;
    @Autowired
    private DorisYcDataDao dorisYcDataDao;
    @Autowired
    private DorisYcDataService dorisYcDataService;
    @Autowired
    private RuntimeDataStatisticsService runtimeDataStatisticsService;
    @Autowired
    private MorningPaperVariablesService morningPaperVariablesService;
    @Autowired
    private SteadyAlarmDataMapper steadyAlarmDataMapper;
    @Autowired
    private UnitDeteriorationAlarmDAO unitDeteriorationAlarmDAO;
    @Autowired
    private RuntimeDataStatisticsDao runtimeDataStatisticsDao;

    private static final List<String> METE_LIST = Lists.newArrayList("1MLD21_CL202_AI", "1MLD21_CP201_AI", "1MLD21_CF221_AI", "2MLD21_CL202_AI", "2MLD21_CP201_AI", "2MLD21_CF221_AI", "3MLD21_CL202_AI", "3MLD21_CP201_AI", "3MLD21_CF221_AI", "4MLD21_CL202_AI", "4MLD21_CP201_AI", "4MLD21_CF221_AI");
    private static final String MLD01 = "MLD01";
    private static final String MLD21 = "MLD21";


    /**
     * 获取上库水位 & 下库水位
     *
     * @return 最新测点数据
     */
    public UpAndDownWaterLevelVo getUpAndDownWaterLevel() {
        List<String> meteCodes = Arrays.asList(MachineAndWorkConditionConst.UP_WATER_LEVEL, MachineAndWorkConditionConst.DOWN_WATER_LEVEL);
        LambdaQueryChainWrapper<DorisYcData> wrapper = new LambdaQueryChainWrapper<>(dorisYcDataDao);
        UpAndDownWaterLevelVo vo = new UpAndDownWaterLevelVo();
        try {
            List<DorisYcData> dataByMeteCodes = wrapper.in(DorisYcData::getMeteCode, meteCodes).list();
            for (DorisYcData data : dataByMeteCodes) {
                if (MachineAndWorkConditionConst.UP_WATER_LEVEL.equals(data.getMeteCode())) {
                    vo.setUpWaterLevel(data.getValue());
                } else if (MachineAndWorkConditionConst.DOWN_WATER_LEVEL.equals(data.getMeteCode())) {
                    vo.setDownWaterLevel(data.getValue());
                }
            }
        } catch (Exception e) {
            log.info("doris异常:{}", e.getMessage());
            vo.setUpWaterLevel("0.0");
            vo.setDownWaterLevel("0.0");
        }
        return vo;
    }


    public PageInfo<RealDataHis> getHis(Date startTime, Date endTime, Long meteId, Integer meteType, PageQuery pageQuery) {
//        if (checkIfUpperThanAMonth(startTime, endTime)) {
//            throw new BusinessException("开始和结束时间超过时间限制");
//        }
        List<RealDataHis> realDataHis = new ArrayList<>();
        try {
            if (MeteTypeEnum.YX.getNum().equals(meteType)) {
                pageQuery.setSortBy("idtime");
                PageExUtil.configPageHelper(pageQuery);
                realDataHis = dataHisTdMapper.pageByTableNameTimeDesc(TableDictConsts.DATA_HIS_PREFIX_YX + meteId, startTime, endTime);
                return new PageInfo<>(realDataHis);
            } else if (MeteTypeEnum.YC.getNum().equals(meteType)) {
                pageQuery.setSortBy("idtime");
                PageExUtil.configPageHelper(pageQuery);
                realDataHis = dataHisTdMapper.pageByTableNameTimeDesc(TableDictConsts.DATA_HIS_PREFIX_YC + meteId, startTime, endTime);
                return new PageInfo<>(realDataHis);
            } else {
                throw new BusinessException("传入的meteType不合法");
            }
        } catch (Exception e) {
            log.error("message:{}", e.getMessage());
            return null;
        }
    }

    public List<MeteDataCockpitDTO> getAllMeteByEquipmentOrSystem(String machineNo, String equipmentCode, Integer meteType) {
        List<DorisYxData> yxList = new ArrayList<>();
        List<DorisYcData> ycList = new ArrayList<>();
        if (!MLD01.equalsIgnoreCase(equipmentCode)) {
            if (meteType == null) {
                yxList = dorisYxDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
                ycList = dorisYcDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
            } else if (MeteTypeEnum.YX.getNum().equals(meteType)) {
                yxList = dorisYxDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
            } else {
                ycList = dorisYcDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
            }
        } else {
            //如果是mld01需要包含三个测点
            if (meteType == null) {
                yxList = dorisYxDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
                ycList = dorisYcDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
                List<DorisYcData> mld21List = dorisYcDataDao.getLessColumnForDownPut(machineNo, MLD21);
                mld21List = mld21List.stream().filter(i -> METE_LIST.contains(i.getMeteCode())).collect(Collectors.toList());
                ycList.addAll(mld21List);
            } else if (MeteTypeEnum.YX.getNum().equals(meteType)) {
                yxList = dorisYxDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
            } else {
                ycList = dorisYcDataDao.getLessColumnForDownPut(machineNo, equipmentCode);
                List<DorisYcData> mld21List = dorisYcDataDao.getLessColumnForDownPut(machineNo, MLD21);
                mld21List = mld21List.stream().filter(i -> METE_LIST.contains(i.getMeteCode())).collect(Collectors.toList());
                ycList.addAll(mld21List);
            }
        }
        List<DorisYxData> yxDataForEquipmentTree = getYxDataForEquipmentTree(machineNo, equipmentCode);
        Map<Long, BaseMete> baseMeteYxCache = getBaseMeteYxCache(
                yxDataForEquipmentTree.stream().map(DorisYxData::getMeteId).collect(Collectors.toList())
        );
        List<MeteDataCockpitDTO> collect = yxList.stream().map(
                dorisYxData -> {
                    MeteDataCockpitDTO meteDataCockpitDTO = new MeteDataCockpitDTO();
                    meteDataCockpitDTO.setValue(generateCockpitDtoValue(MeteTypeEnum.YX.getNum(), dorisYxData.getMeteId(), dorisYxData.getValue(), baseMeteYxCache));
                    meteDataCockpitDTO.setMeteType(MeteTypeEnum.YX.getNum());
                    meteDataCockpitDTO.setMeteName(dorisYxData.getMeteName());
                    meteDataCockpitDTO.setMeteId(dorisYxData.getMeteId());
                    meteDataCockpitDTO.setMeteCode(dorisYxData.getMeteCode());
                    meteDataCockpitDTO.setReportTime(dorisYxData.getReportTime());
                    return meteDataCockpitDTO;
                }
        ).collect(Collectors.toList());
        List<MeteDataCockpitDTO> collect1 = ycList.stream().map(
                dorisYcData -> {
                    MeteDataCockpitDTO meteDataCockpitDTO = new MeteDataCockpitDTO();
                    meteDataCockpitDTO.setValue(generateCockpitDtoValue(MeteTypeEnum.YC.getNum(), dorisYcData.getMeteId(), dorisYcData.getValue(), null));
                    meteDataCockpitDTO.setMeteType(MeteTypeEnum.YC.getNum());
                    meteDataCockpitDTO.setMeteName(dorisYcData.getMeteName());
                    meteDataCockpitDTO.setMeteId(dorisYcData.getMeteId());
                    meteDataCockpitDTO.setMeteCode(dorisYcData.getMeteCode());
                    meteDataCockpitDTO.setReportTime(dorisYcData.getReportTime());
                    return meteDataCockpitDTO;
                }
        ).collect(Collectors.toList());
        collect.addAll(collect1);
        return collect;
    }

    public PageInfo<MeteDataCockpitDTO> getMeteByEquipmentOrSystemPageable(String machineNo, String equipmentCode, Integer meteType, PageQuery pageQuery) {
        if (MeteTypeEnum.YX.getNum().equals(meteType)) {
            List<DorisYxData> yxDataForEquipmentTree = getYxDataForEquipmentTree(machineNo, equipmentCode);
            Map<Long, BaseMete> baseMeteYxCache = getBaseMeteYxCache(
                    yxDataForEquipmentTree.stream().map(DorisYxData::getMeteId).collect(Collectors.toList())
            );
            return PageExUtil.convert(new PageInfo<>(yxDataForEquipmentTree), yxData -> fillDtoFieldForYx(yxData, baseMeteYxCache, meteType));
        } else {
            List<DorisYcData> ycDataForEquipmentTree = getYcDataForEquipmentTree(machineNo, equipmentCode);
            if (MLD01.equalsIgnoreCase(equipmentCode)) {
                List<DorisYcData> list = getYcDataForEquipmentTree(machineNo, METE_LIST);
                list = list.stream().filter(i -> machineNo.equals(i.getMachineNo())).collect(Collectors.toList());
                ycDataForEquipmentTree.addAll(list);
            }
            return PageExUtil.convert(new PageInfo<>(ycDataForEquipmentTree), ycData -> fillDtoFieldForYc(ycData, meteType));
        }
    }

    /**
     * 相同的遥信测点取最新更新的，并重新拼装成List
     */
    private List<DorisYxData> getYxDataForEquipmentTree(String machineNo, String equipmentCode) {
        return dorisYxDataDao.getYxDataInMaxReportTimeByWindow(machineNo, equipmentCode);
    }

    private List<DorisYcData> getYcDataForEquipmentTree(String machineNo, String equipmentCode) {
        return dorisYcDataService.list(
                new LambdaQueryWrapper<DorisYcData>()
                        .like(DorisYcData::getMeteCode, equipmentCode)
                        .eq(DorisYcData::getMachineNo, machineNo)
                        .eq(DorisYcData::getModelUse, MeteModelUse.USED.getNum())
        );
    }

    private List<DorisYcData> getYcDataForEquipmentTree(String machineNo, List<String> meteCode) {
        return dorisYcDataService.list(
                new LambdaQueryWrapper<DorisYcData>()
                        .in(DorisYcData::getMeteCode, meteCode)
                        .eq(DorisYcData::getMachineNo, machineNo)
                        .eq(DorisYcData::getModelUse, MeteModelUse.USED.getNum())
        );
    }

    private MeteDataCockpitDTO fillDtoFieldForYx(DorisYxData data, Map<Long, BaseMete> baseMeteYxCache, Integer meteType) {
        MeteDataCockpitDTO meteDataCockpitDTO = new MeteDataCockpitDTO();
        meteDataCockpitDTO.setMeteName(data.getMeteName());
        meteDataCockpitDTO.setMeteType(MeteTypeEnum.YX.getNum());
        meteDataCockpitDTO.setMeteCode(data.getMeteCode());
        meteDataCockpitDTO.setMeteId(data.getMeteId());
        meteDataCockpitDTO.setReportTime(data.getReportTime());
        meteDataCockpitDTO.setValue(
                generateCockpitDtoValue(meteType, data.getMeteId(), data.getValue(), baseMeteYxCache)
        );
        return meteDataCockpitDTO;
    }

    private MeteDataCockpitDTO fillDtoFieldForYc(DorisYcData data, Integer meteType) {
        MeteDataCockpitDTO meteDataCockpitDTO = new MeteDataCockpitDTO();
        meteDataCockpitDTO.setMeteName(data.getMeteName());
        meteDataCockpitDTO.setMeteType(MeteTypeEnum.YC.getNum());
        meteDataCockpitDTO.setMeteCode(data.getMeteCode());
        meteDataCockpitDTO.setMeteId(data.getMeteId());
        meteDataCockpitDTO.setValue(
                generateCockpitDtoValue(meteType, data.getMeteId(), data.getValue(), null)
        );
        meteDataCockpitDTO.setReportTime(data.getReportTime());
        return meteDataCockpitDTO;
    }

    private String generateCockpitDtoValue(Integer meteType, Long meteId, String value, Map<Long, BaseMete> baseMeteCache) {
        if (meteType.equals(MeteTypeEnum.YX.getNum()) && baseMeteCache != null) {
            BaseMete baseMete = baseMeteCache.get(meteId);
            if (value.equals(String.valueOf(baseMete.getValidMeteValue()))) {
                if (baseMete != null) {
                    return baseMete.getSignalStatusOn();
                }
                return "APPEAR";
            } else if (!value.equals(String.valueOf(baseMete.getValidMeteValue()))) {
                if (baseMete != null) {
                    return baseMete.getSignalStatusOff();
                }
                return "DISAPPEAR";
            } else {
                throw new BusinessException("测点属于遥信但是值不正确：" + meteId);
            }
        } else if (meteType.equals(MeteTypeEnum.YC.getNum())) {
            return new BigDecimal(value).setScale(2, RoundingMode.HALF_UP).toString();
        } else {
            throw new BusinessException("找不到对应的测点类型,meteCode：" + meteId);
        }
    }

    public StartAndStopSimilarDTO startAndStopSimilar(String machineNo, String wfName, List<String> stepsNames) {
        WorkConditionFlow one = workConditionFlowService.getOne(
                new LambdaQueryWrapper<WorkConditionFlow>()
                        .eq(WorkConditionFlow::getMachineNo, machineNo)
                        .eq(WorkConditionFlow::getWfName, wfName)
        );
        Map<Long, List<WorkConditionStepDetail>> stepCollectForDetail = workConditionStepDetailService.list(
                new LambdaQueryWrapper<WorkConditionStepDetail>()
                        .eq(WorkConditionStepDetail::getWfId, one.getId())
                        .eq(WorkConditionStepDetail::getLeaf, 1)
                        .eq(WorkConditionStepDetail::getLabelType, 1)
                        .eq(WorkConditionStepDetail::getType, 0)
        ).stream().collect(Collectors.groupingBy(WorkConditionStepDetail::getStepId));

        StartAndStopSimilarDTO startAndStopSimilarDTO = new StartAndStopSimilarDTO().setSteps(new ArrayList<>());
        Map<Long, WorkConditionStep> stepCollectById = workConditionStepService.list(
                new LambdaQueryWrapper<WorkConditionStep>().in(WorkConditionStep::getId, stepCollectForDetail.keySet())
        ).stream().collect(Collectors.toMap(WorkConditionStep::getId, bean -> bean));

        //TRIGGER ASSESS
        for (Long stepId : stepCollectForDetail.keySet()) {
            List<WorkConditionStepDetail> workConditionStepDetails = stepCollectForDetail.get(stepId);
            for (WorkConditionStepDetail detail : workConditionStepDetails) {
                triggerAssess(detail, machineNo);
            }
        }

        //SLEEP
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            log.error("Interrupted", e);
            Thread.currentThread().interrupt();
        }

        //GET RESULT
        for (Long stepId : stepCollectForDetail.keySet()) {
            WorkConditionStep step = stepCollectById.get(stepId);
            if (!stepsNames.contains(step.getStepName())) {
                continue;
            }
            StartAndStopSimilarStepDTO sAndSStepDTO = new StartAndStopSimilarStepDTO()
                    .setStepConditionId(step.getId())
                    .setName(step.getStepName())
                    .setDelay(
                            generateDelay(step)
                    )
                    .setMeteCode(step.getMeteCode())
                    .setDetails(new ArrayList<>());
            List<WorkConditionStepDetail> workConditionStepDetails = stepCollectForDetail.get(stepId);

            for (WorkConditionStepDetail detail : workConditionStepDetails) {
                sAndSStepDTO.getDetails().add(
                        new StartAndStopSimilarStepDetailDTO()
                                .setDetailId(detail.getId())
                                .setAssessPercent(
                                        generateSimilarPercent(detail, machineNo)
                                )
                                .setExecutorCode(detail.getMeteCode())
                                .setExecutorDescription(detail.getMeteName())
                );
            }
            startAndStopSimilarDTO.getSteps().add(sAndSStepDTO);
        }
        return startAndStopSimilarDTO;
    }

    private String generateDelay(WorkConditionStep step) {
        if (ObjectUtil.isNull(step.getDefaultDelay())) {
            return "/";
        } else {
            return step.getDefaultDelay() + "s";
        }
    }

    private String generateSimilarPercent(WorkConditionStepDetail detail, String machineNo) {
        try {
            return calculateSimilarPercent(detail, machineNo) + "%";
        } catch (BusinessException e) {
            log.info(e.getMessage());
            return "-";
        }
    }

    /**
     * 唤醒评价模型Trigger，与返回结果分开计算
     *
     * @return
     */
    private void triggerAssess(WorkConditionStepDetail detail, String machineNo) {
        Map<String, List<String>> pMeteCode = detail.getPMeteCode();
        for (String stepName : pMeteCode.keySet()) {
            List<String> answerMeteCodeList = pMeteCode.get(stepName);
            for (String answerMeteCode : answerMeteCodeList) {
                assessModelService.wakeAssessByConditionDetail(answerMeteCode, machineNo);
            }
        }
    }

    /**
     * 调用评价触发模型，获取返回值
     *
     * @param detail
     * @return
     * @throws NullPointerException
     */
    private Double calculateSimilarPercent(WorkConditionStepDetail detail, String machineNo) throws BusinessException {
        BigDecimal originalPercent = NUM_ONE;
        Map<String, List<String>> pMeteCode = detail.getPMeteCode();
        for (String stepName : pMeteCode.keySet()) {
            List<String> answerMeteCodeList = pMeteCode.get(stepName);
            for (String answerMeteCode : answerMeteCodeList) {
                BigDecimal answerMeteRate = NUM_ONE;
                if (!assessModelService.checkModelExist(machineNo, answerMeteCode)) {
                    originalPercent = originalPercent.multiply(NUM_ONE);
                } else {
                    List<AwfResultDetailCalVo> lastAwfResultDetails = assessWfResultService.getResultDetailByMeteCode(answerMeteCode);
                    for (AwfResultDetailCalVo awfDetail : lastAwfResultDetails) {
                        BigDecimal failRate = BigDecimal.valueOf(awfDetail.getFailRate());
                        BigDecimal occurProb = BigDecimal.valueOf(awfDetail.getOccurProb());
                        if (NUM_ZERO.compareTo(failRate) == 0) {
                            answerMeteRate = answerMeteRate.multiply(NUM_ONE);
                        } else {
                            answerMeteRate = NUM_ONE.subtract(failRate.multiply(occurProb));
                        }
                    }
                }
                originalPercent = originalPercent.multiply(answerMeteRate);
            }
        }
        return originalPercent.multiply(NUM_HUNDRED).setScale(2, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 从Redis里获取BaseMete对象
     */
    private Map<Long, BaseMete> getBaseMeteYxCache(List<Long> meteIdList) {
        List<String> keys = meteIdList.stream().map(RedisKeyEnum.BASE_METE_ENTITY_YX::key).collect(Collectors.toList());
        List<String> list = RedisUtils.multiGet(keys);
        return list.stream().map(i -> JSON.parseObject(i, BaseMete.class)).collect(Collectors.toMap(BaseMete::getMeteId, entity -> entity));
    }

    public AlarmCountDTO getAlarmCount(String machineNo) {
        LambdaQueryChainWrapper<UnitDeteriorationAlarm> unitWrapper = new LambdaQueryChainWrapper<>(unitDeteriorationAlarmDAO);
        Integer unitAlarmCount = unitWrapper.eq(UnitDeteriorationAlarm::getMachineNo, machineNo)
                .eq(UnitDeteriorationAlarm::getSolved, SolvedEnum.UN_SOLVED.getSolved())
                .count();
        //停机稳态
        Integer stopSteadyAlarmCount = steadyAlarmDataMapper.selectCountBySolvedAndMachineNo(SolvedEnum.UN_SOLVED.getSolved(), machineNo, 0);
        //运行稳态
        Integer runSteadyAlarmCount = steadyAlarmDataMapper.selectCountBySolvedAndMachineNo(SolvedEnum.UN_SOLVED.getSolved(), machineNo, 1);
        return AlarmCountDTO.builder().unitDeteriorationAlarmCount(unitAlarmCount).runSteadyAlarmCount(runSteadyAlarmCount).shutdownSteadyAlarmCount(stopSteadyAlarmCount).build();
    }

    public StartCountStatisticsDTO startCountStatisticsByPaper(String startDate, String endDate, Integer type) {
        return morningPaperVariablesService.startCountStatistics(startDate, endDate, type);
    }

    public RuntimeDataStatisticsCockpitDTO runtimeDataStatistics(String startDate, String endDate) {
        RuntimeDataStatisticsCockpitDTO runtimeDataStatisticsCockpitDTO = new RuntimeDataStatisticsCockpitDTO();
        LambdaQueryChainWrapper<RuntimeDataStatistics> wrapper = new LambdaQueryChainWrapper<>(runtimeDataStatisticsDao);
        List<RuntimeDataStatistics> list = wrapper
                .ge(StringUtils.isNotBlank(startDate), RuntimeDataStatistics::getStatisticsDate, startDate)
                .le(StringUtils.isNotBlank(endDate), RuntimeDataStatistics::getStatisticsDate, endDate)
                .list();
        if (CollectionUtils.isNotEmpty(list)) {
            double actualPowerGeneration = list.stream().filter(i -> Objects.nonNull(i.getActualPowerGeneration())).mapToDouble(RuntimeDataStatistics::getActualPowerGeneration).summaryStatistics().getSum();
            double actualWaterPumpingPower = list.stream().filter(i -> Objects.nonNull(i.getActualWaterPumpingPower())).mapToDouble(RuntimeDataStatistics::getActualWaterPumpingPower).summaryStatistics().getSum();
            double waterGeneratedAmount = list.stream().filter(i -> Objects.nonNull(i.getWaterGeneratedAmount())).mapToDouble(RuntimeDataStatistics::getWaterGeneratedAmount).summaryStatistics().getSum();
            double pumpingVolume = list.stream().filter(i -> Objects.nonNull(i.getPumpingVolume())).mapToDouble(RuntimeDataStatistics::getPumpingVolume).summaryStatistics().getSum();
            runtimeDataStatisticsCockpitDTO.setPumpingVolume(BigDecimal.valueOf(pumpingVolume).setScale(2, RoundingMode.HALF_UP).doubleValue());
            runtimeDataStatisticsCockpitDTO.setActualWaterPumpingPower(actualWaterPumpingPower);
            runtimeDataStatisticsCockpitDTO.setActualPowerGeneration(actualPowerGeneration);
            runtimeDataStatisticsCockpitDTO.setWaterGeneratedAmount(BigDecimal.valueOf(waterGeneratedAmount).setScale(2, RoundingMode.HALF_UP).doubleValue());
        }
        return runtimeDataStatisticsCockpitDTO;
    }
}
